package cn.jly.servlet3.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.UUID;
import java.util.concurrent.Callable;

/**
 * @author lanyangji
 * @description spring mvc支持servlet3.0异步请求测试
 * @date 2020/11/16 上午 9:17
 */
@Controller
public class AsyncController {

    /**
     * 更符合生产实际的异步场景：
     * 一条订单请求 --> 消息队列中间件 --> 监听该中间件的另一个应用监听到订单请求
     *      --> 创建订单并发送给消息中间件  --> 返回
     *
     * @return
     */
    @ResponseBody
    @GetMapping("/async02")
    public DeferredResult<Object> async02() {
        // 此异步方式，需要在指定的时间内，在别的线程或应用或本地添加数据，否则超时并给出超时信息
        final DeferredResult<Object> deferredResult =
                new DeferredResult<>(3000L, "create fail");

        // 一般在别的应用或者线程中给出数据
        //deferredResult.setResult("hello");

        // 存入消息队列
        DeferredResultQueue.add(deferredResult);

        return deferredResult;
    }

    /**
     * 模拟应用监听到消息队列中的消息，创建订单
     *
     * @return
     */
    @ResponseBody
    @GetMapping("/create")
    public String create() {
        final String orderStr = UUID.randomUUID().toString();
        final DeferredResult<Object> deferredResult = DeferredResultQueue.get();
        deferredResult.setResult(orderStr);

        return "success";
    }

    /**
     * spring mvc进行异步处理，只要是将callable提交到taskExecutor，使用一个隔离的线程进行执行
     *
     * spring mvc也支持异步处理拦截器 AsyncHandlerInterceptor
     * @return
     */
    @ResponseBody
    @GetMapping("/async01")
    public Callable<String> async01() {
        System.out.println("主线程开始 " + Thread.currentThread());

        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("辅助线程开始 " + Thread.currentThread());

                Thread.sleep(3000);

                System.out.println("辅助线程结束 " + Thread.currentThread());

                return "async01";
            }
        };

        System.out.println("主线程结束 " + Thread.currentThread());
        return callable;
    }
}
